﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DesignPatterns
{
    /// <summary>
    /// 抽象访问者
    /// 此处可为抽象类或接口，用于声明访问者可以访问哪些元素，具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。
    /// </summary>
    public abstract class Visitor
    {

        public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);

        public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);

    }

    /// <summary>
    /// 具体访问者
    /// 影响访问者访问到一个类后该干什么、怎么干。
    /// </summary>
    public class ConcreteVisitor1 : Visitor
    {

        public override void visitConcreteElementA(ConcreteElementA concreteElementA)
        {
            Console.WriteLine(concreteElementA.GetType().Name + " 被 " + this.GetType().Name + " 访问");

        }

        public override void visitConcreteElementB(ConcreteElementB concreteElementB)
        {
            Console.WriteLine(concreteElementB.GetType().Name + " 被 " + this.GetType().Name + " 访问");

        }

    }

    public class ConcreteVisitor2 : Visitor
    {

        public override void visitConcreteElementA(ConcreteElementA concreteElementA)
        {
            Console.WriteLine(concreteElementA.GetType().Name + " 被 " + this.GetType().Name + " 访问");

        }

        public override void visitConcreteElementB(ConcreteElementB concreteElementB)
        {
            Console.WriteLine(concreteElementB.GetType().Name + " 被 " + this.GetType().Name + " 访问");

        }

    }

    public abstract class Element
    {

        public abstract void accept(Visitor visitor);

    }

    public class ConcreteElementA : Element
    {

        public override void accept(Visitor visitor)
        {
            visitor.visitConcreteElementA(this);
        }

        //其它方法
        public void operationA()
        {
            Console.WriteLine("aaa");

        }

    }

    public class ConcreteElementB : Element
    {

        public override void accept(Visitor visitor)
        {
            visitor.visitConcreteElementB(this);
        }

        //其它方法
        public void operationA()
        {
            Console.WriteLine("BBB");
        }

    }

    public class ObjectStructure
    {

        private List<Element> elements = new List<Element>();

        public void attach(Element element)
        {
            elements.Add(element);
        }

        public void detach(Element element)
        {
            elements.Remove(element);
        }

        public void accept(Visitor visitor)
        {
            foreach (Element element in elements)
            {
                element.accept(visitor);
            }
        }

    }
}
